import * as vscode from 'vscode';
import * as path from 'path';
import { SnippetDefinition, Definitions, FunctionInfo } from '../entities/types';
import { DefinitionType } from '../entities/enum';
import { TreeSitter } from '../../../../core/treesitter/TreeSitter';
import { CxxLanguageServer } from '../services/CxxLanguageServer';
import { getEOL } from '../utils/utils';
import { SyntaxNode } from 'web-tree-sitter';
import { FuncBasicInfoProcessor } from "./FuncBasicInfoProcessor";
import { Logger } from '../../../../src/logger/Logger';

export interface NameAndPos {
  name: string;
  position: vscode.Range;
}

export interface DefsInFunc {
  return: string;
  class: string;
  classCtors: { [key: string]: string[]; };
  classMembers: string[];
  classNamespace: string;
  parameters: string[];
  others: { [key: string]: string[]; }
}


export class ClassifyDefinitionsProcessor {
  public static async classifyDefinitions(definitions: Definitions, funcInfo: FunctionInfo, token?: vscode.CancellationToken): Promise<DefsInFunc> {
    const start = Date.now(); // 记录开始时间
    const res: DefsInFunc = {
      return: '',
      class: '',
      classCtors: {
        public: [],
        protected: [],
        private: []
      },
      classMembers: [],
      classNamespace: '',
      parameters: [],
      others: {
        paramSourceHeaderFile: [],
        paramNamespace: [],
        classCtorsParamDefinition: []
      }
    };

    for (const value of Object.values(definitions)) {
      const definitionList: SnippetDefinition[] = value;
      for (const definition of definitionList) {
        let { type, text, name } = definition;
        const fileName = path.basename(definition.location.uri.path);
        if (type === DefinitionType.enumerator) {
          name = await this.getEnumTypeName(text, 'cpp') ?? name;
        }
        if (name === funcInfo.sourceClassName) {
          const { detailText, classCtors, classMembers, classNamespace, classCtorsParamDefinition } = await this.getDetailDefinition(
            definition, funcInfo, token);
          res.class = this.addFileName(fileName, detailText);
          res.classCtors = classCtors;
          res.classMembers = classMembers;
          res.classNamespace = classNamespace;
          res.others.classCtorsParamDefinition = classCtorsParamDefinition;
        } else if (funcInfo.paramTypeName?.some(item => item === name)) {
          const { detailText, classNamespace } = await this.getDetailDefinition(definition, funcInfo);
          if (detailText !== '') {
            res.parameters.push(this.addFileName(fileName, detailText));
          }
          if (!res.others.paramSourceHeaderFile.includes(fileName)) {
            res.others.paramSourceHeaderFile.push(fileName);
          }
          if (classNamespace?.trim() && !res.others.paramNamespace.includes(classNamespace)) {
            res.others.paramNamespace.push(classNamespace);
          }
        } else if (name === funcInfo.returnTypeName) {
          const { detailText } = await this.getDetailDefinition(definition, funcInfo);
          res.return = this.addFileName(fileName, detailText);
          if (!res.others.paramSourceHeaderFile.includes(fileName)) {
            res.others.paramSourceHeaderFile.push(fileName);
          }
        } else {
          if (res.others[type] === undefined) {
            res.others[type] = [];
          }
          res.others[type].push(this.addFileName(fileName, text));
        }
      }

    }
    const end = Date.now(); // 记录开始时间
    const executionTime = end - start; // 计算执行时间
    Logger.info(`classifyDefinitions success time cost: ${executionTime}ms.`);
    return res;
  }

  private static treeSitterParser = TreeSitter.getInstance();
  private static languageServer = CxxLanguageServer.getInstance();
  private static cppSpecifiers = ['public', 'protected', 'private'];

  public static getFunctionName(node: SyntaxNode, offset: vscode.Position): NameAndPos | undefined {
    const functionDefinition = node.descendantsOfType('function_declarator');
    for (const func of functionDefinition) {
      const res = func.childForFieldName('declarator')?.descendantsOfType('identifier');
      if (res?.length) {
        return { name: res[0].text, position: this.getNodeRange(res[0], offset) };
      }
    }
    return undefined;
  }

  public static getNodeRange(node: SyntaxNode, offset?: vscode.Position): vscode.Range {
    if (offset) {
      return new vscode.Range(
        offset.translate(node.startPosition.row, node.startPosition.column),
        offset.translate(node.endPosition.row, node.endPosition.column)
      );
    } else {
      return new vscode.Range(
        new vscode.Position(node.startPosition.row, node.startPosition.column),
        new vscode.Position(node.endPosition.row, node.endPosition.column)
      );
    }
  }

  private static getSourceClassName(node: SyntaxNode, offset: vscode.Position): NameAndPos | undefined {
    const functionDefinition = node.descendantsOfType('function_declarator');
    for (const func of functionDefinition) {
      const res = func.childForFieldName('declarator')?.descendantsOfType('namespace_identifier');
      if (res?.length) {
        return { name: res[res.length - 1].text, position: this.getNodeRange(res[res.length - 1], offset) };
      }
    }
    return undefined;
  }

  private static getReturnType(node: SyntaxNode, offset: vscode.Position): NameAndPos | undefined {
    const functionDefinition = node.descendantsOfType('function_definition');
    for (const func of functionDefinition) {
      const res = func.childForFieldName('type')?.descendantsOfType('type_identifier');
      if (res?.length) {
        return { name: res[res.length - 1].text, position: this.getNodeRange(res[res.length - 1], offset) };
      }
    }
    return undefined;
  }

  private static getParamTypeAndName(node: SyntaxNode, offset: vscode.Position): { paramTypes: NameAndPos[], paramNames: NameAndPos[] } {
    let paramTypes: NameAndPos[] = [];
    let paramNames: NameAndPos[] = [];
    const paramters = node.descendantsOfType('parameter_declaration');
    paramters.forEach((param: any) => {
      const ptypes = param.descendantsOfType('type_identifier').map((n: any) => {
        return { name: n.text, position: this.getNodeRange(n, offset) };
      });
      const pdeclar = param.childForFieldName('declarator')?.descendantsOfType('identifier');
      paramTypes.push(...ptypes);
      if (pdeclar?.length) {
        paramNames.push({ name: pdeclar[0].text, position: this.getNodeRange(pdeclar[0], offset) });
      }
    });
    return { paramTypes, paramNames };
  }

  private static async getEnumTypeName(text: string, language: string) {
    const tree = this.treeSitterParser.getTree(text, language);
    if (tree) {
      const rootNode = tree.rootNode;
      const enumDefinitions = rootNode.descendantsOfType('enum_specifier');
      for (const enumNode of enumDefinitions) {
        return enumNode.childForFieldName('name')?.text;
      }
    }
    return undefined;
  }

  private static addFileName(fileName: string, detailText: string): string {
    return detailText === '' ? '' : `// ${fileName}\n${detailText}`;
  }

  private static async getDetailDefinition(definition: SnippetDefinition, funcInfo: FunctionInfo, token?: vscode.CancellationToken) {
    if (definition.type === DefinitionType.enum || definition.type === DefinitionType.struct ||
      definition.type === DefinitionType.class || definition.type === DefinitionType.typedef ||
      definition.type === DefinitionType.enumerator) {
      const uri = definition.location.uri;
      const doc = await this.languageServer.getTextDocument(uri.path);
      const symbolChain = await this.getSymbolChain(definition, doc);
      return await this.symbolChainToTexts(symbolChain, doc, funcInfo, token);
    } else {
      return {
        detailText: '',
        classCtors: {
          public: [],
          protected: [],
          private: []
        },
        classMembers: [],
        classNamespace: '',
        classCtorsParamDefinition: []
      };
    }
  }

  public static async getSymbolChain(definition: SnippetDefinition | null, doc: vscode.TextDocument, className?: string, classRange?: vscode.Range) {
    const name = definition?.name || className;
    const range = definition?.location?.range || classRange;
    const resultChain: vscode.DocumentSymbol[] = [];
    if (!range) {
      return resultChain;
    }
    const documentSymbols = await this.languageServer.getDocumentSymbol(doc);
    const containesLineRange = (range1: vscode.Range, range2: vscode.Range): boolean => {
      return range1.start.line <= range2.start.line && range1.end.line >= range2.end.line;
    };
    const hasSameLineRange = (range1: vscode.Range, range2: vscode.Range): boolean => {
      return range1.start.line === range2.start.line && range1.end.line === range2.end.line;
    };
    const searchChildren = (documentSymbols: vscode.DocumentSymbol[]) => {
      const matches = documentSymbols.filter(documentSymbol => containesLineRange(documentSymbol?.range, range));
      for (const m of matches) {
        if (hasSameLineRange(m?.range, range)) {
          resultChain.push(m);
        } else if (m.children.length > 0) {
          resultChain.push(m);
          searchChildren(m.children);
        }
      }
      // typedef类型只能定位到标识符所在行
      if (matches.length === 0) {
        const nameMatches = documentSymbols.filter(
          documentSymbols => containesLineRange(range, documentSymbols?.range) && name === documentSymbols.name
        );
        if (nameMatches.length > 0) {
          const targetSymbol = nameMatches[0];
          targetSymbol.range = range;
          resultChain.push(targetSymbol);
        } else {
          resultChain.length = 0;
        }
      }
    };
    searchChildren(documentSymbols);
    return resultChain;
  }

  private static async symbolChainToTexts(symbolChain: vscode.DocumentSymbol[], doc: vscode.TextDocument, funcInfo: FunctionInfo, token?: vscode.CancellationToken) {
    const detail: string[] = [];
    let classCtors: { [key: string]: string[]; } = {};
    let classMembers: string[] = [];
    let nestedNamespaces: string[] = [];
    let classCtorsParamDefinition: string[] = [];
    const extractDetail = async (symbolChain: vscode.DocumentSymbol[], index: number) => {
      if (symbolChain.length <= index) {
        return;
      }
      const s = symbolChain[index];
      // tag模式下，"#ifndef ALGORITHM_CAMERA_DATA_LISTENER_H"会被识别为namespace
      if (s.kind === vscode.SymbolKind.Namespace && (!s.name.startsWith('#'))) {
        if (s.name) {
          nestedNamespaces.push(s.name);
        }
        detail.push(doc.lineAt(s?.range.start.line).text);
        if (symbolChain.length > index + 1) {
          await extractDetail(symbolChain, index + 1);
        }
        detail.push(doc.lineAt(s?.range.end.line).text);
      } else if (s.kind === vscode.SymbolKind.Enum || s.kind === vscode.SymbolKind.Object) {
        // 枚举和typedef不能嵌套
        const filterEnum = await this.filterEnumAndStructList(
          await this.getFullTextIncludeTemplate(s, doc), funcInfo, s.kind, doc.languageId);
        detail.push(filterEnum);
      } else if (s.kind === vscode.SymbolKind.Struct) {
        if (symbolChain.length > index + 1) {
          /**
           * struct OuterStruct {
           * private:
           *     int outerData;
           * public:
           *     class InnerClass {
           *     public:
           *         int innerData;
           *     };
           * };
           */
          detail.push(...this.definitionBeforeSymbol(s, symbolChain[index + 1], doc));
          await extractDetail(symbolChain, index + 1);
          detail.push(doc.lineAt(s?.range.end.line).text);
        } else {
          const filterStruct = await this.filterEnumAndStructList(
            await this.getFullTextIncludeTemplate(s, doc),
            funcInfo,
            s.kind, doc.languageId);
          detail.push(filterStruct);
        }
      } else if (s.kind === vscode.SymbolKind.Class) {
        if (symbolChain.length > index + 1) {
          // 嵌套类
          detail.push(...this.definitionBeforeSymbol(s, symbolChain[index + 1], doc));
          await extractDetail(symbolChain, index + 1);
          detail.push(doc.lineAt(s?.range.end.line).text);
        } else {
          // 取类名、构造函数、成员变量、访问限定符
          const result = await this.parseClassDefinition(s, doc, funcInfo, token);
          detail.push(...result.sourceClass);
          classCtors = result.classCtors;
          classMembers = result.classMembers;
          classCtorsParamDefinition = result.classCtorsParamDefinition;
        }
      } else {
        await extractDetail(symbolChain, index + 1);
      }
    };
    await extractDetail(symbolChain, 0);
    const detailText = detail.join('\n');
    const classNamespace = nestedNamespaces.join('::');
    return { detailText, classCtors, classMembers, classNamespace, classCtorsParamDefinition };
  }

  private static definitionBeforeSymbol(outerSymbol: vscode.DocumentSymbol, innerSymbol: vscode.DocumentSymbol,
    doc: vscode.TextDocument) {
    const sourceClass: string[] = [];
    // 首先放类起始到第一个成员的内容
    this.definitionBeforeMembers(outerSymbol, doc, sourceClass);
    // 遍历成员
    let lastMemberEndLine: number | undefined = undefined;
    for (let member of outerSymbol.children) {
      // 获取访问限定符
      if (lastMemberEndLine) {
        for (let i = lastMemberEndLine + 1; i < member?.range.start.line; i++) {
          const curText = doc.lineAt(i).text;
          this.addIfIsSpecifierLine(curText, sourceClass);
        }
      }
      if (member === innerSymbol) {
        break;
      }
      lastMemberEndLine = member?.range.end.line;
    }
    return sourceClass;
  }

  private static async parseClassDefinition(s: vscode.DocumentSymbol, doc: vscode.TextDocument, funcInfo?: FunctionInfo, token?: vscode.CancellationToken) {
    const sourceClass: string[] = [];
    const classCtors: { [key: string]: string[]; } = {
      public: [], protected: [], private: []
    };
    const classMembers: string[] = [];
    let classCtorsParamDefinition: string[] = [];
    // 如果是空类，直接放全部内容，保留缩进
    if (!s.children.length) {
      sourceClass.push(this.getFullText(s, doc));
    } else {
      classCtorsParamDefinition = await this.getConstructorParameterDefinition(s, doc, funcInfo, token);
      // 首先放类起始到第一个成员的内容
      const curSpec = this.definitionBeforeMembers(s, doc, sourceClass);
      // 遍历成员
      this.definitionOfClassMembers(s, doc, sourceClass, classCtors, classMembers, curSpec, funcInfo);
      // 最后放最后一个成员到类结束的内容
      this.definitionAfterMembers(s, doc, sourceClass);
    }
    return { sourceClass, classCtors, classMembers, classCtorsParamDefinition };
  }

  /**
   * 解析类定义或结构体定义中，第一个成员之前的部分，存于sourceClass变量中
   * @param s 类或结构体对应的符号表示
   * @param doc 当前文档
   * @param sourceClass 截取的类或结构体的必要定义
   * @returns 下方成员的访问限定符
   */
  private static definitionBeforeMembers(symbol: vscode.DocumentSymbol, doc: vscode.TextDocument, texts: string[]) {
    let curSpec = undefined;
    const startPart: string[] = [];
    // 为避免第一个访问限定符多余，只能逐行添加
    for (let i = symbol?.range.start.line; i < symbol.children[0]?.range.start.line; i++) {
      const curText = doc.lineAt(i).text;
      if (this.addIfIsSpecifierLine(curText, startPart)) {
        curSpec = this.getSpecifierFromLastLine(startPart);
        continue;
      }
      const trimedCurText = curText.trim();
      if (trimedCurText !== '' && !trimedCurText.startsWith('//')) {
        startPart.push(curText);
      }
    }
    texts.push(...startPart.join('\n').replace(/\/\*[\s\S]*?\*\//g, '').split('\n'));
    return curSpec;
  }

  private static async definitionOfClassMembers(s: vscode.DocumentSymbol, doc: vscode.TextDocument, sourceClass: string[],
    classCtors: { [key: string]: string[]; }, classMembers: string[], startSpec?: string, funcInfo?: FunctionInfo) {
    let lastMemberEndLine: number | undefined = undefined;
    let isAbstractClass: boolean = false;
    // 类成员默认访问权限是private
    let curSpec = startSpec ?? 'private';
    for (const member of s.children) {
      // 获取访问限定符
      if (lastMemberEndLine) {
        for (let i = lastMemberEndLine + 1; i < member?.range.start.line; i++) {
          const curText = doc.lineAt(i).text;
          if (this.addIfIsSpecifierLine(curText, sourceClass)) {
            curSpec = this.getSpecifierFromLastLine(sourceClass);
          }
        }
      }
      // 获取构造函数和成员变量定义
      if (await this.isAddMemberToClassDefine(member, doc, s.name)) {
        const text = this.getFullText(member, doc);
        sourceClass.push(text);
        classCtors[curSpec].push(text.trim().replace(/;+$/, ''));
      } else if (funcInfo?.memberVariables?.has(member.name)) {
        const text = this.getFullText(member, doc);
        sourceClass.push(text);
        classMembers.push(`${curSpec}: ${text.trim()}`);
      } else if (member.name === funcInfo?.sourceFuncName) {
        const isStatic = this.getFullText(member, doc).trimStart().startsWith('static ');
        if (funcInfo) {
          funcInfo.signature = `${curSpec} : ${isStatic ? 'static ' : ''}${funcInfo?.signature}`;
        }
      } else if (!isAbstractClass) {
        // 判断是否纯虚类,只需找到一个纯虚函数
        // TAG模式下，member的range只包含函数名，因此签名换行的纯虚函数会被忽略
        const text = this.getFullText(member, doc);
        if (/virtual [\s\S]*\([\s\S]*\)\s*=\s*0;/g.test(text)) {
          sourceClass.push(text);
          isAbstractClass = true;
        }
      }
      lastMemberEndLine = member?.range.end.line;
    }
    this.removeUselessSpecifier(sourceClass);
  }

  private static async isAddMemberToClassDefine(symbol: vscode.DocumentSymbol, doc: vscode.TextDocument, sName: string): Promise<boolean> {
    const memberName = symbol.name;
    if (memberName === sName || memberName.toLowerCase() === 'getinstance') {
      return true;
    } else {
      const text = this.getFullText(symbol, doc);
      // 如果是析构函数
      const destructorName = await this.getDestructorName(text, doc.languageId)
      if (destructorName?.length) {
        return true;
      }
      const identifier = text.split(memberName);
      const identifierList = identifier[0].split(/::|&|\*|<|>|\(|\)|,|=/);
      // 标识符集合中是否存在目标类的类名
      return identifierList.includes(sName);
    }
  }

  private static async getDestructorName(code: string, language: string): Promise<string[]> {
    const tree = this.treeSitterParser.getTree(code, language);
    if (tree) {
      const destructorName = this.treeSitterParser.getTargetNodeText(tree.rootNode, ['destructor_name']);
      return destructorName;
    }
    return [];
  }

  private static removeUselessSpecifier(output: string[]) {
    const trimedLastText = this.getSpecifierFromLastLine(output);
    if (this.cppSpecifiers.some(item => item === trimedLastText)) {
      output.pop();
    }
  }

  private static getSpecifierFromLastLine(output: string[]) {
    return output[output.length - 1].trim().slice(0, -1).trimEnd();
  }

  private static definitionAfterMembers(s: vscode.DocumentSymbol, doc: vscode.TextDocument, sourceClass: string[]) {
    sourceClass.push(doc.getText(new vscode.Range(
      new vscode.Position(s.children[s.children.length - 1]?.range.end.line + 1, 0),
      doc.lineAt(s?.range.end.line)?.range.end
    )));
  }

  /**
   * 检查当前行是否为 private: 或 protected: 或 private: ，如果是，将其添加到输出类定义中
   * @param line 当前行
   * @param sourceClass 输出类定义
   * @returns 是否访问控制符所在行
   */
  private static addIfIsSpecifierLine(line: string, sourceClass: string[]) {
    const curSpec = line.trim().slice(0, -1);
    if (this.cppSpecifiers.some(item => item === curSpec)) {
      this.removeUselessSpecifier(sourceClass);
      sourceClass.push(line.replace(curSpec, `${curSpec} `));
      return true;
    }
    return false;
  }

  // 获取被测类构造函数的入参类定义
  private static async getConstructorParameterDefinition(symbol: vscode.DocumentSymbol, doc: vscode.TextDocument, funcInfo?: FunctionInfo, token?: vscode.CancellationToken): Promise<string[]> {
    if (!token || !funcInfo) {
      return [];
    }
    const memberVariables = Array.from(funcInfo.memberVariables || new Set());
    const res: Set<string> = new Set<string>();
    const text = doc.getText(symbol?.range);
    const tree = this.treeSitterParser.getTree(text, doc.languageId,);
    if (!tree) {
      return [];
    }
    const functionDefinition = this.treeSitterParser.getTargetNode(tree.rootNode, ['function_definition', 'field_declaration']);
    const startLine = symbol?.range.start.line;
    for (let i = 0; i < functionDefinition.length; i++) {
      const s = functionDefinition[i];
      const start = s.startPosition.row + startLine;
      const end = s.endPosition.row + startLine;
      const range = new vscode.Range(start, s.startPosition.column, end, s.endPosition.column);
      const position = new vscode.Position(s.startPosition.row, s.startPosition.column);
      const sfuncInfo = await FuncBasicInfoProcessor.extract(doc, position, range);
      if (sfuncInfo.sourceFuncName === funcInfo.sourceFuncName) {
        continue;
      }
      if (sfuncInfo.sourceFuncName && (sfuncInfo.sourceFuncName === symbol.name || memberVariables.includes(sfuncInfo.sourceFuncName))) {
        const definition = await this.getTargetDefinition(sfuncInfo, range, doc, token);
        definition && res.add(definition);
      }
    }
    return Array.from(res);
  }

  private static async getTargetDefinition(funcInfo: FunctionInfo, range: vscode.Range, doc: vscode.TextDocument, token?: vscode.CancellationToken) {
    if (!funcInfo.paramTypeName?.length) {
      return '';
    }
    const { signatureRange } = this.getSignatureAndFucBodyRange(doc, range);
    const signatureDefinitions: SnippetDefinition[] = await this.languageServer.getSnippetDefinition({ document: doc, range: signatureRange, allowedTypes: ['class'], token });
    for (const definition of signatureDefinitions) {
      if (funcInfo?.paramTypeName.some(item => item === definition.name)) {
        return definition.text;
      }
    }
    return '';
  }

  public static getSignatureAndFucBodyRange(doc: vscode.TextDocument, funcRange: vscode.Range): { signatureRange: vscode.Range, funcBodyRange: vscode.Range | null } {
    const codeLines = doc.getText().split(getEOL(doc));
    const signatureStartLine = funcRange.start.line;
    let signatureEndLine: number = 0;
    let signatureEndColumn: number = 0;
    for (let i = signatureStartLine; i < codeLines.length; i++) {
      const line = codeLines[i];
      if (line.includes('{')) {
        signatureEndLine = i;
        signatureEndColumn = line.indexOf('{');
        break;
      }
    }
    if (signatureEndLine < signatureStartLine) {
      // 没有函数体
      return { signatureRange: funcRange, funcBodyRange: null }
    }
    const signatureRange = new vscode.Range(signatureStartLine, 0, signatureEndLine, signatureEndColumn);
    const funcBodyStart = new vscode.Position(signatureEndLine, signatureEndColumn + 1);
    const funcBodyRange = new vscode.Range(funcBodyStart, funcRange.end);
    return { signatureRange, funcBodyRange };
  }

  private static getFullText(symbol: vscode.DocumentSymbol, doc: vscode.TextDocument) {
    return doc.getText(new vscode.Range(
      new vscode.Position(symbol?.range.start.line, 0),
      doc.lineAt(symbol?.range.end.line)?.range.end
    ));
  }

  private static async filterEnumAndStructList(text: string, funcInfo: FunctionInfo, type: number, language: string): Promise<string> {
    let memberVariables = Array.from(funcInfo.memberVariables || new Set());
    const enumAndStructList = await this.getEnumAndStructListNode(text, language);
    // 如果成员变量集合长度小于10，则不做裁剪
    if (enumAndStructList.length <= 10) {
      return text;
    }
    const firstCurlyBraceIndex = text.indexOf('{');
    const lastCurlyBraceIndex = text.lastIndexOf('}');
    const content = text.substring(firstCurlyBraceIndex + 1, lastCurlyBraceIndex);
    if (!content) {
      return text;
    }
    let validList: string[] = [];
    let identifierName: string = '';
    let partitionCharacter: string = '';
    let filterText: string = '';
    switch (type) {
      case vscode.SymbolKind.Enum:
        identifierName = 'identifier';
        partitionCharacter = ',\r\n';
        break;
      case vscode.SymbolKind.Struct:
        identifierName = 'field_identifier';
        partitionCharacter = '\r\n';
        break;
      default:
        break;
    }
    // 检查数组最后一项
    const checkLastItem = () => {
      const lastItem = validList.slice(-1)[0];
      if (lastItem && this.isIncludeAccessControlChar(lastItem)) {
        validList.pop();
      }
    };
    for (let node of enumAndStructList) {
      // 如果存在访问控制符
      if (this.isIncludeAccessControlChar(node.text)) {
        checkLastItem();
        const text = `${node.text}:`;
        validList.push(text);
        continue;
      }
      const identifier = this.treeSitterParser.getTargetNodeText(node, [identifierName]);
      if (!identifier) {
        continue;
      }
      if (memberVariables.includes(identifier[0])) {
        validList.push(node.text);
      }
    }
    if (!validList.length) {
      return '';
    }
    checkLastItem();
    // 替换整个大括号中的内容
    filterText = text.replace(content, '\r\n' + validList.join(partitionCharacter) + '\r\n');
    return filterText;
  }

  private static isIncludeAccessControlChar(text: string) {
    if (!text) {
      return false;
    };
    const ACCESS_CONTROL_CHAR = ['private', 'protected', 'public'];
    for (const char of ACCESS_CONTROL_CHAR) {
      if (text.includes(char)) {
        return true;
      }
    }
    return false;
  };

  private static async getFullTextIncludeTemplate(symbol: vscode.DocumentSymbol, doc: vscode.TextDocument) {
    const res = await this.findTemplateDeclaration(symbol?.range, doc);
    const templateLine = res?.templateLine || symbol?.range.start.line;
    return doc.getText(new vscode.Range(
      new vscode.Position(templateLine, 0),
      doc.lineAt(symbol?.range.end.line)?.range.end
    ));
  }

  public static async findTemplateDeclaration(range: vscode.Range, doc: vscode.TextDocument): Promise<{ templateLine: number, templateText: string } | null> {
    const docLines = doc.getText().split(getEOL(doc));
    const startLine = range.start.line;
    if (startLine === 0) {
      return null;
    }
    let templateLine = startLine;
    let templateText = '';
    // 从下往上找到第一个
    for (let lineNumber = startLine - 1; lineNumber >= 0; lineNumber--) {
      const line = docLines[lineNumber];
      if (line.trim()) {
        const tree = this.treeSitterParser.getTree(line, doc.languageId);
        const template = tree?.rootNode.descendantsOfType('template');
        if (template) {
          templateLine = lineNumber;
          templateText = line;
        }
        break;
      }
    }
    if (templateLine === startLine) {
      return null;
    }
    return { templateLine, templateText };
  }

  private static async getEnumAndStructListNode(code: string, language: string): Promise<SyntaxNode[] | []> {
    const tree = this.treeSitterParser.getTree(code, language);
    if (!tree) {
      return [];
    }
    const targetNode = this.treeSitterParser.getTargetNode(tree.rootNode, ['enumerator_list', 'field_declaration_list']);
    let enumList: SyntaxNode[] = [];
    targetNode[0]?.children?.forEach((node: any) => {
      node.isNamed && enumList.push(node);
    });
    return enumList;
  }
}